#include "ErathostenesSieve.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErathostenesSieve
 *      Method:  calculatePrimes
 * Description:  Calcula valores primos até o valor max, incluindo-o
 *--------------------------------------------------------------------------------------
 */
void ErathostenesSieve::calculatePrimes(uint max)
{
    uint top = primes.size();

    primes.reserve(max);

    /* Adiciona mais posições no vetor, inicializando-os como true */
    for(uint i = top; i <= max; i++)
        primes.push_back(true);

    /* Calcula o menor valor inteiro maior que a raiz quadrada de max */
    uint root = (uint) ceil(sqrt(max));

    /* Verifica os números de 2 até a root */
    for(uint i = 2; i <= root; i++)
    {
        if(primes[i])
        {
            /* Calcula o proximo valor acima de top que seja divisivel por i */
            uint init = top + i - top % i;
            /* Min=2*i, para evitar recálculo podemos usar init */
            uint vmax = (2 * i > init) ? 2 * i : init;

            /* Marca os múltiplos de i como não primo */
            for(uint j = vmax; j <= max; j += i)
                primes[j] = false;
        }
    }
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErathostenesSieve
 *      Method:  isPrime
 * Description:  Retorna verdadeiro se o número for primo; falso caso contrário
 *--------------------------------------------------------------------------------------
 */
bool ErathostenesSieve::isPrime(uint number)
{
    /* Se o número a ser verificado é maior que máximo calculado,
     * é feito o cálculo de primos até esse número (por demanda) */
    if(number >= primes.size())
    {
        uint diff = number - primes.size(); /* Calcula o quanto a mais deve ser calculado */
        uint will = (uint) ceil(diff / (float) MIN_RESIZE); /* Calcula em função de MIN_RESIZE */
        calculatePrimes(primes.size() + MIN_RESIZE * will);
    }
    return primes[number];
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErathostenesSieve
 *      Method:  isPrime
 * Description:  Verifica se a soma ASCII da palavra é um número primo
 *--------------------------------------------------------------------------------------
 */
bool ErathostenesSieve::isPrime(const string& s)
{
    uint size = s.length();
    uint sum = 0;

    /* Faz a soma dos caracteres alfanuméricos da string */
    for(uint i = 0; i < size; i++)
        if(isalnum(s[i]))
            sum += s[i];

    /* Retorna o retorno do método isPrime do crivo */
    return isPrime(sum);
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErathostenesSieve
 *      Method:  checkForPrimes
 * Description:  Procura por palavras/frases primas nos palíndromos
 *--------------------------------------------------------------------------------------
 */
uint ErathostenesSieve::checkForPrimes(Palindromes *palins)
{
    uint sum = 0;

    for(uint i = 0; i < palins->size(); i++)
    {
        Palindrome *p = palins->at(i);
        if(isPrime(p->palindrome))
        {
            p->isPrime = 1;
            sum++;
        }
        else
            p->isPrime = 0;
    }

    return sum;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErathostenesSieve
 *      Method:  operator<<
 * Description:  Imprime todos os números primos calculados
 *--------------------------------------------------------------------------------------
 */
ostream& operator<<(ostream& os, ErathostenesSieve &sieve)
{
    for(uint i = 2; i < sieve.primes.size(); i++)
        if(sieve.primes[i])
            os << i << endl;
    return os;
}

